package com.hliushi.mp;


import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @ClassName Demo01UserFunctionalInterface
 * @Description 内置函数式接口 由来
 * @Author hliushi
 * @Date 2021/9/2 10:45
 * @Version V1.0
 **/
@FunctionalInterface
interface Operator<T> {
    T getSum(T[] arr);
}

public class Demo01UserFunctionalInterface {

    public static void main(String[] args) {
        Integer[] arr = {1, 2, 8, 3, 4, 10, 2, 0, 9};

        // 调用函数式接口中的方法
        method((num) -> {
            // 这部分逻辑可以视为, Operator实现类的逻辑
            int sum = 0;
            for (int n : num) {
                sum += n;
            }
            return sum;
        }, arr);

        // --------------------------------------------
        System.out.println("--------------------------------------------");
        printMax(() -> {
            // 先排序, 最后就是最大的
            Arrays.sort(arr);
            // 最后就是最大的
            return arr[arr.length - 1];
        });

        System.out.println("arr = " + Arrays.toString(arr));

        System.out.println("--------------------------------------------");
        // 使用Lambda表达式将一个字符串转成大写和小写的字符串
        upperAndLower((str) -> {
            System.out.println("lowerCase = " + str.toLowerCase());
            System.out.println("upperCase = " + str.toUpperCase());
        });


        System.out.println("--------------------------------------------");
        // 使用Lambda表达式将字符串转成数字, 并扩大十倍
        str2Num((str) -> Integer.parseInt(str) * 10);

        System.out.println("--------------------------------------------");
        // 使用Lambda判断一个人名如果超过三个字符就认为很长的名字
        nameLengthJudge(str -> str.length() > 3, "上树立以");
    }


    /**
     * 使用自定义的函数式接口作为方法参数
     *
     * @param op
     * @param arr
     */
    public static void method(Operator<Integer> op, Integer[] arr) {
        int sum = op.getSum(arr);
        System.out.println("sum = " + sum);
    }


    /**
     * Supplier<T>接口, 它意味着"供给", 对应的Lambda表达式需要 "对外提供" 一个符合泛型类型的对象数据
     * #
     * 无参有返回值类型
     *
     * @param supplier
     */
    public static void printMax(Supplier<Integer> supplier) {
        Integer max = supplier.get();
        System.out.println("max = " + max);
    }


    /**
     * Consumer<T>接口则正好相反, 它不是生成一个数据, 而是消费一个数据, 其数据类型由泛型参数决定
     * #
     * 有参无返回值类型
     *
     * @param consumer 消费型接口, 可以拿到accept方法参数传递过来的数据进行处理, 有参无返回的接口
     */
    public static void upperAndLower(Consumer<String> consumer) {
        consumer.accept("helloWorld");
    }


    /**
     * Function<T, R>接口用来根据一个类型的数据得到另一个类型的数据,
     * 前者称为前置条件, 后者称为后置条件
     * <p>
     * public interface Function<T, R> {
     * .    public abstract R apply(T t);
     * }
     * #
     * 有参数有返回值
     *
     * @param function Function转换型接口, 对apply方法传入的T类型数据进行处理, 返回R类型的结果, 有参有返回的接口
     */
    public static void str2Num(Function<String, Integer> function) {
        Integer in = function.apply("10");
        System.out.println("in = " + in);
    }


    /**
     * Predicate接口, 需要对某种数据类型进行判断, 从而得到一个boolean值结果
     * <p>
     * public interface Predicate<T> {
     * .    public abstract boolean test(T t);
     * }
     * #
     * 有参数有返回值, 但返回值是一个boolean类型
     *
     * @param predicate
     * @param str
     */
    public static void nameLengthJudge(Predicate<String> predicate, String str) {
        boolean veryLong = predicate.test(str);
        System.out.println("名字很长吗 = " + veryLong);
    }
}
